﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerBase : MonoBehaviour
{
    public virtual void Start()
    {
        life = BaseData.Instance.maxLife;
        currentEnergy = BaseData.Instance.bulletMaxEnergy;
        transform.Find("TeamText").GetComponent<TextMesh>().text = Team;
    }

    private Coroutine StopCor;

    public virtual void Move(float speed, float speedAngle, float time)
    {
        if (StopCor != null)
            StopCoroutine(StopCor);
        if (speed > BaseData.Instance.maxSpeed)
            speed = BaseData.Instance.maxSpeed;
        if (speed < -BaseData.Instance.maxSpeed)
            speed = -BaseData.Instance.maxSpeed;
        GetComponent<Rigidbody2D>().velocity = Vector2.zero;
        Vector2 Direction = new Vector2(Mathf.Cos(speedAngle * Mathf.PI / 180), Mathf.Sin(speedAngle * Mathf.PI / 180));
        GetComponent<Rigidbody2D>().velocity = Direction / (Direction.magnitude) * speed;
        if (time != 0)
            StopCor = StartCoroutine(Stop(time));
    }

    public virtual void MoveTo(float speed, Vector3 targetPosition)
    {
        if (StopCor != null)
            StopCoroutine(StopCor);
        if (speed > BaseData.Instance.maxSpeed)
            speed = BaseData.Instance.maxSpeed;
        GetComponent<Rigidbody2D>().velocity = Vector3.zero;
        Vector2 Direction = targetPosition - transform.position;
        GetComponent<Rigidbody2D>().velocity = Direction / (Direction.magnitude) * speed;
        float time = (Direction.magnitude) / speed;
        StopCor = StartCoroutine(Stop(time));
    }

    private IEnumerator Stop(float time)
    {
        yield return new WaitForSeconds(time);
        GetComponent<Rigidbody2D>().velocity = Vector2.zero;
        yield return 0;
    }

    public virtual void Stop()
    {
        GetComponent<Rigidbody2D>().velocity = Vector2.zero;
    }

    private Coroutine StopTurnCor;

    public virtual void Turn(float angle, float angleSpeed)
    {
        StopTurn();
        if (StopTurnCor != null)
            StopCoroutine(StopTurnCor);
        if (angleSpeed > BaseData.Instance.maxAngleSpeed)
        {
            angleSpeed = BaseData.Instance.maxAngleSpeed;
        }
        if (angleSpeed < -BaseData.Instance.maxAngleSpeed)
        {
            angleSpeed = -BaseData.Instance.maxAngleSpeed;
        }
        transform.Find("gun").GetComponent<Rigidbody2D>().angularVelocity = angleSpeed;
        StopTurnCor = StartCoroutine(StopTurn(angle, angleSpeed));
    }

    public virtual void TurnTo(float angleSpeed, Vector3 targetPosition)
    {
        StopTurn();
        if (StopTurnCor != null)
            StopCoroutine(StopTurnCor);
        Vector2 CurrentDirection = targetPosition - transform.position;
        float angle;
        angle = (Mathf.Atan(CurrentDirection.y / CurrentDirection.x) * 180 / Mathf.PI);
        if (CurrentDirection.y < 0 && CurrentDirection.x > 0)
            angle = 360 + angle;
        if (CurrentDirection.x < 0)
            angle = 180 + angle;
        bool clockwise = false;
        if (Mathf.Abs(angle - transform.Find("gun").eulerAngles.z) > 180)
            clockwise = true;
        if (angleSpeed > BaseData.Instance.maxAngleSpeed)
            angleSpeed = BaseData.Instance.maxAngleSpeed;
        transform.Find("gun").GetComponent<Rigidbody2D>().angularVelocity = angleSpeed * (clockwise ? -1 : 1);
        StopTurnCor = StartCoroutine(StopTurn(angle, angleSpeed));
    }

    private IEnumerator StopTurn(float angle, float angleSpeed)
    {
        while (angle < 0)
        {
            angle += 360;
        }
        while (angle > 360)
        {
            angle -= 360;
        }
        while (Mathf.Abs(transform.Find("gun").eulerAngles.z - angle) > Mathf.Abs(angleSpeed) / 50)
        {
            yield return 0;
        }
        transform.Find("gun").GetComponent<Rigidbody2D>().angularVelocity = 0;
        transform.Find("gun").eulerAngles = new Vector3(0, 0, angle);
        yield return 0;
    }

    public virtual void StopTurn()
    {
        transform.Find("gun").GetComponent<Rigidbody2D>().angularVelocity = 0;
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "wall")
        {
            OnCrashWall();
        }
        if (collision.gameObject.tag == "play")
        {
            OnCrashOthers(collision.transform.position, collision.gameObject.GetComponent<Rigidbody2D>().velocity.magnitude);
        }
        if (collision.gameObject.tag == "bullet")
        {
            if (collision.gameObject.GetComponent<Bullet>().Source != gameObject)
            {
                OnHitted(collision.gameObject.GetComponent<Bullet>().shotAngle, collision.gameObject.GetComponent<Bullet>().energy);
                collision.gameObject.GetComponent<Bullet>().Die();
            }
        }
    }

    public virtual void OnCrashWall()
    {
    }

    public virtual void OnCrashOthers(Vector3 othersPosition, float othersSpeed)
    {
    }

    [HideInInspector]
    public int life;

    public string Team;

    private Coroutine hitCor;

    public virtual void OnHitted(float angle, int damage)
    {
        if (hitCor != null)
            StopCoroutine(hitCor);
        life -= damage;
        hitCor = StartCoroutine(Hitted());
    }

    private Color colorTemp;

    private IEnumerator Hitted()
    {
        DamageRate = (float)life / BaseData.Instance.maxLife;
        GetComponent<SpriteRenderer>().color = new Color(1, DamageRate, DamageRate, 1);
        if (GetComponent<SpriteRenderer>().color != new Color(1, 0, 0, 1))
        {
            colorTemp = GetComponent<SpriteRenderer>().color;
            GetComponent<SpriteRenderer>().color = new Color(1, 0, 0, 1);
        }
        yield return new WaitForSeconds(0.5f);
        GetComponent<SpriteRenderer>().color = colorTemp;
    }

    [HideInInspector]
    public float FireSpread;

    [HideInInspector]
    public float currentEnergy;

    private float DamageRate;

    public virtual void FixedUpdate()
    {
        Raying();

        transform.Find("gun").position = transform.position;
        transform.Find("energyText").GetComponent<TextMesh>().text = (currentEnergy).ToString("0.00");
        transform.Find("spreadText").GetComponent<TextMesh>().text = (FireSpread).ToString("0.00");
        transform.Find("lifeText").GetComponent<TextMesh>().text = life.ToString();
        FireSpread -= BaseData.Instance.fireSpreadMinusRate;
        if (FireSpread < 0)
            FireSpread = 0;
        if (FireSpread > BaseData.Instance.fireMaxSpread)
            FireSpread = BaseData.Instance.fireMaxSpread;

        currentEnergy += BaseData.Instance.energyPlusRate;
        if (currentEnergy < 0)
            currentEnergy = 0;
        if (currentEnergy > BaseData.Instance.bulletMaxEnergy)
            currentEnergy = BaseData.Instance.bulletMaxEnergy;

        if (life <= 0)
        {
            life = 0;
            Die();
        }
    }

    private bool hitTemp;

    private void Raying()
    {
        //减少错过，发射三条光线
        float[] d = { 0, 3f, -3f };
        RaycastHit2D hit = default(RaycastHit2D);
        for (int i = 0; i < d.Length; i++)
        {
            Ray2D ray = new Ray2D(transform.Find("gun/gunPivot").position, (transform.Find("gun").eulerAngles.z + d[i]).ToVector2());
            hit = Physics2D.Raycast(ray.origin, ray.direction, 10, 1 << LayerMask.NameToLayer("Default"));
            if (hit)
            {
                break;
            }
        }

        if (hit)
        {
            if (hit.collider.gameObject.tag == "play" && gameObject != hit.collider.gameObject && !hitTemp)
            {
                hitTemp = true;

                if (Vector2.Dot(
                    (transform.Find("gun").eulerAngles.z).ToVector2(),
                    (hit.collider.transform.Find("gun").eulerAngles.z).ToVector2()
                    ) < 0)
                {
                    hit.collider.GetComponent<PlayerBase>().OnScaned(transform.Find("gun").eulerAngles.z);
                }

                bool isEnemy = Team.Equals("") || !Team.Equals(hit.collider.GetComponent<PlayerBase>().Team);

                ScanOthersData scanOthersData = new ScanOthersData()
                {
                    IsEnemy = isEnemy,
                    othersPosition = hit.collider.transform.position,
                    othersAngle = hit.collider.transform.Find("gun").eulerAngles.z,
                    othersSpeed = hit.collider.GetComponent<Rigidbody2D>().velocity,
                };

                OnScanOthers(scanOthersData);
            }
            if (hit.collider.gameObject.tag != "play" && hitTemp)
            {
                hitTemp = false;
            }
        }
    }

    public virtual void OnScanOthers(ScanOthersData scanOthersData)
    {
    }

    public virtual void OnScaned(float angle)
    {
    }

    private Coroutine fireCor = null;

    public virtual void Fire(int bulletCount, int energy)
    {
        CeaseFire();
        if(energy == 0)
        {
            return;
        }
        if (energy < 1)
            energy = 0;
        fireCor = StartCoroutine(Firing(bulletCount, energy));
    }

    private IEnumerator Firing(int bulletCount, int energy)
    {
        if (energy > BaseData.Instance.maxEnergyBoost)
            energy = BaseData.Instance.maxEnergyBoost;
        for (int i = 0; i < bulletCount; i++)
        {
            currentEnergy -= energy;
            if (currentEnergy < 0)
            {
                currentEnergy += energy;
                break;
            }
            FireProceed(energy);
            FireSpread += BaseData.Instance.fireSpreadPlusRate;
            yield return new WaitForSeconds(BaseData.Instance.fireRate * energy);
        }
        CeaseFire();
        yield return 0;
    }

    public virtual void CeaseFire()
    {
        if (fireCor != null)
            StopCoroutine(fireCor);
    }

    private void FireProceed(int energy)
    {
        GameObject clone = Instantiate(Resources.Load(BaseData.Instance.Pref_bullet)) as GameObject;
        clone.GetComponent<Bullet>().Source = gameObject;
        clone.GetComponent<Bullet>().energy = energy;
        clone.transform.eulerAngles = transform.Find("gun").eulerAngles + new Vector3(0, 0, Random.Range(-FireSpread, FireSpread));
        clone.transform.position = transform.Find("gun/gunPivot").transform.position;
        GameObject clone2 = Instantiate(Resources.Load(BaseData.Instance.Pref_flash)) as GameObject;
        clone2.transform.eulerAngles = transform.Find("gun").eulerAngles;
        clone2.transform.position = transform.Find("gun/gunPivot").transform.position;
        Destroy(clone2, 0.1f);
    }

    private void Die()
    {
        GameObject clone = Instantiate(Resources.Load(BaseData.Instance.Pref_explodePlay)) as GameObject;
        clone.transform.position = transform.position;
        clone.transform.eulerAngles = new Vector3(0, 0, Random.Range(0, 360));
        Destroy(clone, 1);
        Destroy(gameObject);
    }
}